#include "complex_trail.h"
#include "math/math_core.h"
#include "math/mat4x4.h"
#include "math/intersection.h"
#include "num/rand.h"
#include "graphics/graphics_util.h"

#include "util/log.h"				// log
#include "util/common_macros.h"		// macros

#include <cassert>

using namespace vfx;

// used by all effects

ComplexTrail::ComplexTrail() :
	m_NodeA(NULL),
	m_AddNode(0.1f),
	m_DropNode(0.5f),
	m_NodeC(0),m_LowNode(0), m_HighNode(0),
	m_pImage(0),
	m_Additive(true),
	m_Width(3.0f/800.0f)
{
}


ComplexTrail::~ComplexTrail()
{
	UTIL_SAFE_DELETEA(m_NodeA);
}


void	ComplexTrail::SetImage(const std::string& Name)
{
	m_pImage = GetGraphics()->LoadImageFromFile(Name);
}


void	ComplexTrail::Tick(float dt)
{
	m_AddNode.Tick(dt);
	m_DropNode.Tick(dt);
	if (m_LowNode == m_HighNode)
	{
		m_DropNode.SetLimit(m_Timeout);
	}
	if (m_DropNode.IsReady() && m_LowNode < m_HighNode)
	{
		m_LowNode++;
		m_DropNode.SetLimit(m_GenTime);
	}
}


void	ComplexTrail::Render(const math::Vec2& Offset, float Scale)
{
	if (!m_pImage) return;
	if (m_HighNode==m_LowNode) return;

	Graphics* pG = GetGraphics();
	const COLOR	c = 0xFFFFFFFF;
	int	Index = 0;
	Graphics::Vertex2D*	VertA = Graphics::GetTempVert();
	
	if (m_Additive)
    {
		GetGraphics()->SetupAdditiveAlpha(true);
	} 

	// rewrite as strip instead?

	Index = GraphicsUtil::FillPath(Offset, Scale, &m_NodeA[m_LowNode], (m_HighNode-m_LowNode), m_Width, VertA, Graphics::MAX_TEMP_VERT);
	if (Index > 0 ) 
	{
		pG->SetTexture(0,m_pImage);
		pG->DrawVertex2D(VertA, Index);
	}
	if (m_Additive)
    {
		GetGraphics()->SetupAdditiveAlpha(false);
    } 
}

void	ComplexTrail::UpdatePos(const math::Vec2& Pos)
{
	if (m_AddNode.IsReady())
	{
		assert(m_HighNode < m_NodeC);
		m_NodeA[m_HighNode++] = Pos;
		if (m_HighNode>=m_NodeC)
		{
			CopyNodes();
		}
		m_AddNode.Reset();

	}
}

void	ComplexTrail::Clear()
{
	m_HighNode = m_LowNode = 0;
	m_AddNode.SetLimit(m_GenTime);
	m_DropNode.SetLimit(m_Timeout);
}

void	ComplexTrail::CreateNodes(float	GenTime, float Timeout)
{
	UTIL_SAFE_DELETEA(m_NodeA);
	m_NodeC = (int)((1.0f / GenTime) * Timeout * 2.0f);
	m_NodeA = new math::Vec2[m_NodeC];
	m_LowNode = m_HighNode = 0;
	m_GenTime = GenTime;
	m_Timeout = Timeout;
	m_AddNode.SetLimit(m_GenTime);
	m_DropNode.SetLimit(m_Timeout);
}

void	ComplexTrail::CopyNodes()
{
	if (m_HighNode - m_LowNode > 0)
	memcpy(&m_NodeA[0], m_NodeA[m_LowNode], (m_HighNode - m_LowNode) * sizeof(math::Vec2));
	m_HighNode = m_HighNode - m_LowNode;
	UTIL_CLAMP(m_HighNode, 0, m_NodeC-1);
	m_LowNode = 0;
}

